package org.example.controller;

import cn.hutool.core.img.ImgUtil;
import cn.hutool.extra.qrcode.QrCodeUtil;
import cn.hutool.extra.qrcode.QrConfig;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.swing.filechooser.FileSystemView;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URL;

/**
 * 二维码工具-QrCodeUtil
 *
 * @author wangMaoXiong
 * @version 1.0
 * @date 2021/3/13 11:21
 */
@RestController
@RequestMapping("/code")
@SuppressWarnings("all")
public class QRCodeController {

    private static final Logger LOGGER = LoggerFactory.getLogger(QRCodeController.class);
    /**
     * 生成二维码·最简单的方式1
     *
     * @param codeContent ：二维码内容
     * @return
     */
    @GetMapping("/qrCode1")
    public void qrCode1(@RequestParam String codeContent, HttpServletResponse response) {
        LOGGER.info("生成二维码·最简单的方式1，codeContent={}", codeContent);
        ServletOutputStream outputStream = null;
        try {
            outputStream = response.getOutputStream();
            /**
             * 生成二维码到输出流
             *
             * @param content   文本内容
             * @param width     宽度
             * @param height    高度
             * @param imageType 图片类型（图片扩展名），见{@link ImgUtil}
             * @param out       目标流
             */
            QrCodeUtil.generate(codeContent, 300, 300, ImgUtil.IMAGE_TYPE_GIF, outputStream);
        } catch (IOException e) {
            e.printStackTrace();
            LOGGER.error("生成二维码·最简单的方式1失败", e);
        } finally {
            if (outputStream != null) {
                try {
                    outputStream.flush();
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 生成二维码·最简单的方式2
     *
     * @param codeContent ：二维码内容
     * @return
     */
    @GetMapping("/qrCode1_2")
    public void qrCode1_2(@RequestParam String codeContent, HttpServletResponse response) {
        LOGGER.info("生成二维码·最简单的方式2，codeContent={}", codeContent);
        ServletOutputStream outputStream = null;
        try {
            outputStream = response.getOutputStream();
            /**
             * 生成二维码图片
             * @param content 文本内容
             * @param width   宽度
             * @param height  高度
             * @return 二维码图片（黑白）
             */
            BufferedImage bufferedImage = QrCodeUtil.generate(codeContent, 300, 300);

            /**
             * BufferedImage generate(String content, QrConfig config): 生成二维码图片
             * @param content 文本内容
             * @param config  二维码配置，包括长、宽、边距、颜色等
             * @return 二维码图片（黑白）
             */
            /**
             * BufferedImage write(RenderedImage im,String formatName,OutputStream output)
             * 将图片写入到指定的输出流
             */
            ImageIO.write(bufferedImage, "gif", outputStream);
        } catch (IOException e) {
            e.printStackTrace();
            LOGGER.error("生成二维码·最简单的方式2失败", e);
        } finally {
            if (outputStream != null) {
                try {
                    outputStream.flush();
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 生成二维码·自定义参数·设置中间的 logo
     *
     * @param codeContent ：二维码内容
     * @return
     */
    @GetMapping("/qrCode2")
    public void qrCode2(@RequestParam String codeContent, HttpServletResponse response) {
        LOGGER.info("生成二维码·自定义参数·设置中间的 logo,codeContent={}", codeContent);

        ServletOutputStream outputStream = null;
        // 获取类路径下的 logo 文件
        URL resource = QRCodeController.class.getClassLoader().getResource("static/images/0_wangmx1993328.png");
        String file = resource.getFile();
        try {
            outputStream = response.getOutputStream();

            //二维码设置
            QrConfig config = new QrConfig(300, 300);
            config.setMargin(3);// 设置边距，既二维码和背景之间的边距
            config.setForeColor(Color.CYAN);// 设置前景色，既二维码颜色（青色）
            config.setBackColor(Color.GRAY);// 设置背景色（灰色）
            config.setImg(file);//设置二维码中的Logo文件，内部会自动调整 logo 的尺寸

            /**
             * 很多时候，二维码无法识别，这时就要调整纠错级别。
             * ErrorCorrectionLevel枚举选项包括：L、M、Q、H，级别由低到高（默认为 M）。
             * 低级别的像素块更大，可以远距离识别，但是遮挡就会造成无法识别；高级别则相反，像素块小，允许遮挡一定范围，但是像素块更密集。
             */
            config.setErrorCorrection(ErrorCorrectionLevel.H);
            /**
             * 生成二维码到输出流
             *
             * @param content   文本内容
             * @param config    二维码配置，包括长、宽、边距、颜色、logo 等
             * @param imageType 图片类型（图片扩展名），见{@link ImgUtil}
             * @param out       目标流
             */
            QrCodeUtil.generate(codeContent, config, ImgUtil.IMAGE_TYPE_GIF, outputStream);
        } catch (IOException e) {
            e.printStackTrace();
            LOGGER.error("生成二维码·自定义参数·设置中间的 logo失败", e);
        } finally {
            if (outputStream != null) {
                try {
                    outputStream.flush();
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 生成二维码或条形码图片
     *
     * @param codeContent ：内容，注意：条形码不支持中文，否则报错，二维码才支持中文。
     * @param response
     */
    @GetMapping("/qrCode3")
    public void qrCode3(@RequestParam String codeContent, HttpServletResponse response) {
        LOGGER.info("生成二维码或条形码图片，codeContent={}", codeContent);

        ServletOutputStream outputStream = null;
        try {
            outputStream = response.getOutputStream();
            /**
             * 生成二维码或条形码图片.千万注意 条形码不支持中文
             * @param content 文本内容
             * @param format  格式，可选二维码(QR_CODE)或者条形码（CODABAR、CODE_39、CODE_93、CODE_128...）。
             * @param width   宽度
             * @param height  高度
             * @return 二维码图片（黑白）
             */
            BufferedImage bufferedImage = QrCodeUtil.generate(codeContent, BarcodeFormat.CODE_128, 300, 100);
            ImageIO.write(bufferedImage, "gif", outputStream);
        } catch (IOException e) {
            LOGGER.error("生成二维码或条形码图片失败", e);
        } finally {
            if (outputStream != null) {
                try {
                    outputStream.flush();
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 生成二维码或条形码图片
     *
     * @param codeContent ：内容，注意：条形码不支持中文，否则报错，二维码才支持中文。
     * @param response
     */
    @GetMapping("/qrCode4")
    public void qrCode4(@RequestParam String codeContent, HttpServletResponse response) {
        LOGGER.info("生成二维码或条形码图片，codeContent={}", codeContent);

        ServletOutputStream outputStream = null;
        try {
            outputStream = response.getOutputStream();

            //二维码、或者条形码设置
            QrConfig config = new QrConfig(300, 100);
            config.setMargin(2);// 设置边距，既二维码和背景之间的边距
            config.setForeColor(Color.darkGray);// 设置前景色，既二维码颜色（深灰色）
            config.setBackColor(Color.pink);// 设置背景色（粉色）

            /**
             * 生成二维码或条形码图片.千万注意 条形码不支持中文
             * @param content 文本内容
             * @param format  格式，可选二维码(QR_CODE)或者条形码（CODABAR、CODE_39、CODE_93、CODE_128...）。
             * @param width   宽度
             * @param height  高度
             * @return 二维码图片（黑白）
             */
            BufferedImage bufferedImage = QrCodeUtil.generate(codeContent, BarcodeFormat.CODE_128, config);
            ImageIO.write(bufferedImage, "gif", outputStream);
        } catch (IOException e) {
            LOGGER.error("生成二维码或条形码图片失败",e);
        } finally {
            if (outputStream != null) {
                try {
                    outputStream.flush();
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 生成二维码到文件进行存储。底层其实就是先生成二维码，然后保存到文件中
     *
     * @param codeContent
     * @param response
     */
    @GetMapping("/qrCode5")
    public void qrCode5(@RequestParam String codeContent, HttpServletResponse response) {
        LOGGER.info("生成二维码到文件进行存储，codeContent={}", codeContent);

        ServletOutputStream outputStream = null;
        FileInputStream inputStream = null;

        //让二维码文件输出到桌面
        File homeDirectory = FileSystemView.getFileSystemView().getHomeDirectory();
        File targetFile = new File(homeDirectory, System.currentTimeMillis() + ".gif");
        try {
            outputStream = response.getOutputStream();
            /**
             * 生成二维码到文件，二维码图片格式取决于文件的扩展名
             *
             * @param content    文本内容
             * @param width      宽度
             * @param height     高度
             * @param targetFile 目标文件，扩展名决定输出格式。文件不存在时自动创建
             * @return 目标文件
             */
            File file = QrCodeUtil.generate(codeContent, 300, 300, targetFile);

            /**
             * 生成二维码到文件，二维码图片格式取决于文件的扩展名
             * @param content    文本内容
             * @param config     二维码配置，包括长、宽、边距、颜色等
             * @param targetFile 目标文件，扩展名决定输出格式
             * @return 目标文件
             * File generate(String content, QrConfig config, File targetFile)
             */

            //将桌面生成好的二维码文件采用最原始的读写文件方式，输出到页面的 img
            inputStream = new FileInputStream(file);
            int size = 0;
            byte[] readBytes = new byte[1024];
            while ((size = inputStream.read(readBytes)) > 0) {
                outputStream.write(readBytes, 0, readBytes.length);
            }
            LOGGER.info("二维码文件存储在：{}" , file.getAbsolutePath());
        } catch (IOException e) {
            LOGGER.error("生成二维码到文件进行存储失败", e);
        } finally {
            if (outputStream != null) {
                try {
                    outputStream.flush();
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 生成 Base64 编码格式的二维码，以 String 形式表示
     *
     * @param codeContent
     * @param response
     * @return
     */
    @GetMapping("/qrCode6")
    public String qrCode6(@RequestParam String codeContent, HttpServletResponse response) {
        response.setContentType("text/text;charset=UTF-8");
        LOGGER.info("生成 Base64 编码格式的二维码，以 String 形式表示,codeContent={}", codeContent);

        //二维码、或者条形码设置
        QrConfig config = new QrConfig(300, 300);
        config.setMargin(2);// 设置边距，既二维码和背景之间的边距
        config.setForeColor(Color.white);// 设置前景色，既二维码颜色（黄色）
        config.setBackColor(Color.darkGray);// 设置背景色（深灰色）
        /**
         * 生成 Base64 编码格式的二维码，以 String 形式表示
         * 输出格式为: data:image/[type];base64,[data]，type 可以是常见的 gif、png、jpeg、x-icon 等等，data 是 base64编码的图片数据
         * @param content   内容
         * @param qrConfig  二维码配置，包括长、宽、边距、颜色等
         * @param imageType 图片类型（图片扩展名），见{@link ImgUtil}
         * @return 图片 Base64 编码字符串，而且已经包括前面固定且必须写死的格式，返回后无需再处理：data:image/[type];base64,
         */
        String base64 = QrCodeUtil.generateAsBase64(codeContent, config, ImgUtil.IMAGE_TYPE_PNG);
        /**
         * String generateAsBase64(String content, QrConfig qrConfig, String imageType, byte[] logo)
         * String generateAsBase64(String content, QrConfig qrConfig, String imageType, Image logo)
         * String generateAsBase64(String content, QrConfig qrConfig, String imageType, String logoBase64)
         */
        System.out.println(base64);
        return base64;
    }

    /**
     * String decode(File qrCodeFile)： 解码二维码图片为文本
     * String decode(Image image):  将二维码图片解码为文本
     * String decode(InputStream qrCodeInputstream) ： 解码二维码图片为文本
     * String decode(Image image, boolean isTryHarder, boolean isPureBarcode):将二维码图片解码为文本
     *
     * @param image         {@link Image} 二维码图片
     * @param isTryHarder   是否优化精度
     * @param isPureBarcode 是否使用复杂模式，扫描带logo的二维码设为true
     * @param args
     */

    public static void main(String[] args) {

    }
}
